﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using RapidSalesAdminPortalAPI.DataAccess;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebAPI.Common;
using WebAPI.Common.Attributes;
using WebAPI.Models;
using WebAPI.Util;

namespace WebAPI.Controllers
{
    [AllowAnonymous]
    [Route("api/[controller]")]
    [ApiController]
    public class LoginController : ParentController
    {
        private readonly RS_AdmPortalContext _context;
        //private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IConfiguration _configuration;
        private readonly ILogUtility _logUtility;
        private readonly ILogger _logger;
        private readonly IDataProtectorUtility _dataProtectorUntility;

        public LoginController(RS_AdmPortalContext context,  IConfiguration configuration, ILogUtility logUtility, ILogger<LoginController> logger, IDataProtectorUtility dataProtectorUntility)
        {
            _context = context;
            //_httpContextAccessor = httpContextAccessor; IHttpContextAccessor httpContextAccessor,
            _configuration = configuration;
            _logUtility = logUtility; // sample code for DI of common utility class
            _logger = logger;
            _dataProtectorUntility = dataProtectorUntility;
        }


        [HttpPost]
        [Log("Login", "Login", description: "Login/Login", LogType: Enums.LogType.AdministratorAccountLog)]
        public async Task<ActionResult<ResultMsg>> Login([FromBody] LoginModel model)
        {
            ResultMsg resultMsg = new();
            try
            {
                _logUtility.WriteMessage($"{model.Username} tried to log in"); // sample code for DI of common utility class
                _logger.LogInformation("INFO: Login API visited at {DT}", DateTime.UtcNow.ToLongTimeString()); //sample code for calling global logger of ASP.NET Core
                _logger.LogWarning("WARNING: Login API visited at {DT}", DateTime.UtcNow.ToLongTimeString()); //sample code for calling global logger of ASP.NET Core
                object obj = new();
                var user = _context.FrIpAdministratorAccounts.FirstOrDefault(u => u.LoginName == model.Username);

                if (user == null)
                {
                    return resultMsg.SetResultMsg((int)ResultCode.LoginNameNotExists,
                        HelperUtility.GetDescription(ResultCode.LoginNameNotExists),
                        null);
                }
                if (user != null)
                {
                    if (!user.Enable)
                    {
                        return resultMsg.SetResultMsg((int)ResultCode.LoginNameHasDisable,
                             HelperUtility.GetDescription(ResultCode.LoginNameHasDisable),
                       null);
                    }
                    //var userRoles = await userManager.GetRolesAsync(user);
                    var authClaims = new List<Claim>
                    {
                        new Claim("LoginName", user.LoginName),
                        new Claim("Id",user.Id.ToString()),
                        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    };

                    //foreach (var userRole in userRoles)
                    //{
                    //    authClaims.Add(new Claim(ClaimTypes.Role, userRole));
                    //}
                    if (MD5Encryption.Compare(model.Password, user?.Password ?? ""))
                    {
                        var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"]));

                        var token = new JwtSecurityToken(
                            issuer: _configuration["JWT:ValidIssuer"],
                            audience: _configuration["JWT:ValidAudience"],
                            expires: DateTime.Now.AddDays(1),
                            claims: authClaims,
                            signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256)
                            );
                        user.LoginFailedCount = 0; //login success change FailedLoginCount 0
                        user.LastLoginTime = DateTime.Now;
                        _context.Entry(user).State = EntityState.Modified;
                        await _context.SaveChangesAsync();
                        string accessToken = new JwtSecurityTokenHandler().WriteToken(token);
                        resultMsg = resultMsg.SetResultMsg((int)ResultCode.Success,
                                    HelperUtility.GetDescription(ResultCode.Success),
                                    new
                                    {
                                        token = accessToken,
                                        loginName = user.LoginName,
                                        expiration = token.ValidTo
                                    });
                        return resultMsg;
                    }
                    else
                    {
                        //var data = _context.FrIpMasterData.FirstOrDefault(it => it.Code == "Administrator Configuration" && it.ItemTypeName == "Fail Login Count Limit");

                        var data = _context.FrIpMasterData.FirstOrDefault(it => it.Code == "Fail Login Count Limit" && it.OptionSetGroup == "4");

                        int loginFailedCount = 5;
                        if (data != null && !string.IsNullOrWhiteSpace(data.Value))
                        {
                            loginFailedCount = Convert.ToInt32(data.Value);
                        }
                        user.LoginFailedCount += 1;
                        //5 is manage set
                        if (user.LoginFailedCount > loginFailedCount)
                        {
                            user.Enable = false; //change account status to disable
                            obj = new { Enabled = false };
                        }
                        _context.Entry(user).State = EntityState.Modified;
                        await _context.SaveChangesAsync();
                        return resultMsg.SetResultMsg((int)ResultCode.PasswordError,
                          HelperUtility.GetDescription(ResultCode.PasswordError),
                          obj);
                    }
                }
                return resultMsg;

            }
            catch (Exception ex)
            {
                _logger.LogError(ex.Message);
                resultMsg = resultMsg.SetResultMsg((int)ResultCode.LogInFailed,
                           HelperUtility.GetDescription(ResultCode.LogInFailed),
                           null);
                return resultMsg;
            }
         }
    }
}
